﻿<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="pragma" content="no-cache" />
    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate" />
    <meta http-equiv="expires" content="0" />
    <title>FaceCat-Html5</title>
</head>
<body>
    <canvas id="pyCanvas" width="400" height="700" style="position: fixed; left: 0px; top: 0px;" />
    <script type="text/javascript" src="facecat.js"></script>
    <script type="text/javascript">
        let canvasPy = document.getElementById("pyCanvas"); //绘图区域
        canvasPy.width = window.innerWidth;
        canvasPy.height = window.innerHeight;
        let paintPy = new FCPaint(); //绘图对象
        paintPy.canvas = canvasPy;
        scaleCanvas(paintPy);
        //判断主题色
        paintPy.defaultUIStyle = "dark";
        let url = location.href;
        if (url.indexOf("color=light") != -1) {
            paintPy.defaultUIStyle = "light";
        }
        //判断是否移动端
        paintPy.isMobile = isMobileMode();
        if (paintPy.isMobile) {
            paintPy.scaleFactorX = 2.5;
            paintPy.scaleFactorY = 2.5;
        }
        addDefaultEvent(canvasPy, paintPy);
        //面积图数据
        class PyrometerData extends FCView {
            constructor() {
                super();
                this.value = 0; //数值
                this.key = null;
                this.open = 0;
                this.close = 0;
                super.viewType = "pdata"; //类型
            }
        }

        /*
        * 面积图
        */
        class PyrometerDiv extends FCView {
            constructor() {
                super();
                this.useAnimation = false; //是否使用动画
                super.viewType = "pyrometer"; //类型
                this.INF = 0x3f3f3f; //无效数据
                this.Rwidth = 0 //横向宽度
                this.Rheight = 0; //纵向宽度
                this.rects = new Array(); //显示区域
            }
        }

        //创建买卖档
        let pyrometer = new PyrometerDiv();
        pyrometer.dock = "fill";
        //添加到框架
        addView(pyrometer, paintPy);
        //根据主题色配色
        if (pyrometer.paint.defaultUIStyle == "dark") {
            pyrometer.backColor = "rgb(0,0,0)";
            pyrometer.borderColor = "rgb(100,100,100)";
            pyrometer.textColor = "rgb(255,255,255)";
        } else if (pyrometer.paint.defaultUIStyle == "light") {
            pyrometer.backColor = "rgb(255,255,255)";
            pyrometer.borderColor = "rgb(150,150,150)";
            pyrometer.textColor = "rgb(0,0,0)";
        }
        //计算大小
        let layoutrow = function (pyrometer, R, w) {
            let width = pyrometer.size.cx;
            let height = pyrometer.size.cy;
            let lx = width - pyrometer.Rwidth;
            let ly = height - pyrometer.Rheight;
            let direction = 0;  // 0: horizontal;  1: vertical

            // refresh Rwidth, Rheight
            let sum = 0;
            for (let x = 0; x < R.length; x++) {
                sum += R[x];
            }
            let ext = sum / w;
            if (Math.abs(w - pyrometer.Rwidth) <= 1e-6) {
                pyrometer.Rheight -= ext;
                direction = 0;
            }
            else {
                pyrometer.Rwidth -= ext;
                direction = 1;
            }

            // store
            for (let x = 0; x < R.length; x++) {
                let r = R[x];
                if (direction == 0) {
                    let hh = ext, ww = r / ext;
                    let newRect = new FCRect(0, 0, 0, 0);
                    newRect.left = lx;
                    newRect.top = ly;
                    newRect.right = lx + ww;
                    newRect.bottom = ly + hh;
                    pyrometer.rects.push(newRect);
                    // refresh
                    lx += ww;
                }
                else {
                    let ww = ext, hh = r / ext;
                    let newRect = new FCRect(0, 0, 0, 0);
                    newRect.left = lx;
                    newRect.top = ly;
                    newRect.right = lx + ww;
                    newRect.bottom = ly + hh;
                    pyrometer.rects.push(newRect);
                    // refresh
                    ly += hh;
                }
            }
        };

        //计算横向宽度
        let rWidth = function (pyrometer, R, w) {
            return Math.min(pyrometer.Rwidth, pyrometer.Rheight);
        };

        //计算最差结果
        let worst = function (pyrometer, R, w) {
            if (R.length == 0) {
                return pyrometer.INF;
            }
            let rmx = 0, rmn = pyrometer.INF, s = 0;
            for (let x = 0; x < R.length; x++) {
                let r = R[x];
                s += r;
                if (r > rmx) rmx = r;
                if (r < rmn) rmn = r;
            }
            let pw = Math.pow(w, 2), sw = Math.pow(s, 2);
            let res = Math.max(pw * rmx / sw, sw / (pw * rmn));
            return Math.max(pw * rmx / sw, sw / (pw * rmn));
        };

        /*
        * 动画秒表
        */
        let onPyrometerTime = function (pyrometer) {
            let paint2 = false;
            if (pyrometer.useAnimation) {
                for (let i = 0; i < pyrometer.rects.length; i++) {
                    let subView = pyrometer.views[i];
                    let targetRect = pyrometer.rects[i];
                    let nowRect = new FCRect(subView.location.x, subView.location.y, subView.location.x + subView.size.cx, subView.location.y + subView.size.cy);
                    if (true) {
                        if (nowRect.left > targetRect.left) {
                            nowRect.left -= (nowRect.left - targetRect.left) / 4;
                            if (nowRect.left - targetRect.left < 10) {
                                nowRect.left = targetRect.left;
                            }
                            paint2 = true;
                        }
                        else if (nowRect.left < targetRect.left) {
                            nowRect.left += (targetRect.left - nowRect.left) / 4;
                            if (targetRect.left - nowRect.left < 10) {
                                nowRect.left = targetRect.left;
                            }
                            paint2 = true;
                        }
                    }

                    if (true) {
                        if (nowRect.top > targetRect.top) {
                            nowRect.top -= (nowRect.top - targetRect.top) / 4;
                            if (nowRect.top - targetRect.top < 10) {
                                nowRect.top = targetRect.top;
                            }
                            paint2 = true;
                        }
                        else if (nowRect.top < targetRect.top) {
                            nowRect.top += (targetRect.top - nowRect.top) / 4;
                            if (targetRect.top - nowRect.top < 10) {
                                nowRect.top = targetRect.top;
                            }
                            paint2 = true;
                        }
                    }

                    if (true) {
                        if (nowRect.right > targetRect.right) {
                            nowRect.right -= (nowRect.right - targetRect.right) / 4;
                            if (nowRect.right - targetRect.right < 10) {
                                nowRect.right = targetRect.right;
                            }
                            paint2 = true;
                        }
                        else if (nowRect.right < targetRect.right) {
                            nowRect.right += (targetRect.right - nowRect.right) / 4;
                            if (targetRect.right - nowRect.right < 10) {
                                nowRect.right = targetRect.right;
                            }
                            paint2 = true;
                        }
                    }
                    if (true) {
                        if (nowRect.bottom > targetRect.bottom) {
                            nowRect.bottom -= (nowRect.bottom - targetRect.bottom) / 4;
                            if (nowRect.bottom - targetRect.bottom < 10) {
                                nowRect.bottom = targetRect.bottom;
                            }
                            paint2 = true;
                        }
                        else if (nowRect.bottom < targetRect.bottom) {
                            nowRect.bottom += (targetRect.bottom - nowRect.bottom) / 4;
                            if (targetRect.bottom - nowRect.bottom < 10) {
                                nowRect.bottom = targetRect.bottom;
                            }
                            paint2 = true;
                        }
                    }
                    subView.location = new FCPoint(nowRect.left, nowRect.top);
                    subView.size = new FCSize(nowRect.right - nowRect.left, nowRect.bottom - nowRect.top);
                }
            } else {
                for (let i = 0; i < pyrometer.rects.length; i++) {
                    let subView = pyrometer.views[i];
                    let targetRect = pyrometer.rects[i];
                    subView.location = new FCPoint(targetRect.left, targetRect.top);
                    subView.size = new FCSize(targetRect.right - targetRect.left, targetRect.bottom - targetRect.top);
                }
            }
            if (paint2) {
                invalidateView(pyrometer);
            }
        };

        /*
        * 更新数据
        */
        let updatePyromoter = function (pyrometer) {
            pyrometer.rects = new Array();
            let totalAmount = 0;
            for (let i = 0; i < pyrometer.views.length; i++) {
                totalAmount += pyrometer.views[i].value;
            }
            let rates = new Array();
            for (let i = 0; i < pyrometer.views.length; i++) {
                rates.push(pyrometer.views[i].value / totalAmount);
            }
            pyrometer.Rwidth = pyrometer.size.cx;
            pyrometer.Rheight = pyrometer.size.cy;
            let areas = new Array();
            for (let i = 0; i < rates.length; i++) {
                areas.push(rates[i] * pyrometer.size.cx * pyrometer.size.cy);
            }
            let children = areas;
            let row = new Array();
            let w = Math.min(pyrometer.Rwidth, pyrometer.Rheight);
            while (true) {
                if (pyrometer.rects.length > pyrometer.views.length) {
                    break;
                }
                if (w <= 0) {
                    break;
                }
                if (children.length == 0) {
                    if (row.length > 0) {
                        layoutrow(pyrometer, row, w);  // output current row
                    }
                    break;
                }

                //
                let c = children[0];
                if (c == 0) {
                    break;
                }
                let newrow = new Array();
                for (let x = 0; x < row.length; x++) {
                    newrow.push(row[x]);
                }
                newrow.push(c);
                if (worst(pyrometer, row, w) >= worst(pyrometer, newrow, w)) {  // can be placed in this row
                    //cout << " add: " << c << endl;
                    let tmp = new Array();
                    for (let x = 1; x < children.length; x++) {
                        tmp.push(children[x]);
                    }
                    children = tmp;
                    row = newrow;
                }
                else {  // placed in a empty new row
                    //cout << " new: " << c << endl;
                    layoutrow(pyrometer, row, w);  // output current row
                    row = new Array();
                    w = rWidth(pyrometer, row, parseInt(w));
                }
            }
        };

        /*
        * 重绘背景的实现方法
        * view:视图
        * paint:绘图对象
        * clipRect:裁剪区域
        */
        paintPy.onPaint = function (view, paint, clipRect) {
            onPaintDefault(view, paint, clipRect);
            if (view.viewType == "pyrometer") {
                drawDiv(view, paint, clipRect);
            } else if (view.viewType == "pdata") {
                let diffRange = ((view.close - view.open) / view.close * 100).toFixed(2) + "%";
                let backColor = null;
                if (view.parent.paint.defaultUIStyle == "dark") {
                    if (view.close >= view.open) {
                        backColor = "rgb(219,68,83)";
                    } else {
                        backColor = "rgb(15,193,118)";
                    }
                } else if (view.parent.paint.defaultUIStyle == "light") {
                    if (view.close >= view.open) {
                        backColor = "rgb(255,255,255)";
                    } else {
                        backColor = "rgb(255,255,255)";
                    }
                }
                paint.fillRect(backColor, 0, 0, view.size.cx, view.size.cy);
                let fontSize1 = parseInt(Math.min(view.size.cx, view.size.cy) / 5);
                if (fontSize1 > 1) {
                    let baseUpper = "Code1";
                    let font1 = "Default," + fontSize1;
                    let tSize = paint.textSize(baseUpper, font1);
                    while (tSize.cx > view.size.cx - 10) {
                        fontSize1 -= 1;
                        if (fontSize1 < 1) {
                            return;
                        }
                        font1 = "Default," + fontSize1;
                        tSize = paint.textSize(baseUpper, font1);
                    }
                    let quoteUpper = "Code2";
                    let font2 = "Default," + (fontSize1 / 2);
                    let tSize2 = paint.textSize(quoteUpper, font2);
                    if (view.parent.paint.defaultUIStyle == "dark") {
                        paint.drawText(baseUpper, "rgb(255,255,255)", font1, (view.size.cx - tSize.cx) / 2, view.size.cy / 2 - tSize.cy - tSize.cy / 2);
                        paint.drawText(quoteUpper, "rgb(255,255,255)", font2, (view.size.cx - tSize2.cx) / 2, view.size.cy / 2 - tSize2.cy / 2);
                    } else if (view.parent.paint.defaultUIStyle == "light") {
                        paint.drawText(baseUpper, "rgb(0,0,0)", font1, (view.size.cx - tSize.cx) / 2, view.size.cy / 2 - tSize.cy - tSize.cy / 2);
                        paint.drawText(quoteUpper, "rgb(0,0,0)", font2, (view.size.cx - tSize2.cx) / 2, view.size.cy / 2 - tSize2.cy / 2);
                    }

                    let strPrice = view.close.toFixed(6);
                    let font3 = "Default," + (fontSize1 * 2 / 3);
                    let tSize5 = paint.textSize(strPrice, font3);
                    if (view.parent.paint.defaultUIStyle == "dark") {
                        paint.drawText(strPrice, "rgb(255,255,255)", font3, (view.size.cx - tSize5.cx) / 2, view.size.cy / 2 + tSize.cy - tSize5.cy / 2);
                    } else if (view.parent.paint.defaultUIStyle == "light") {
                        paint.drawText(strPrice, "rgb(0,0,0)", font3, (view.size.cx - tSize5.cx) / 2, view.size.cy / 2 + tSize.cy - tSize5.cy / 2);
                    }
                }
            }
        };

        /*
        * 重绘边框的实现方法
        * view:视图
        * paint:绘图对象
        * clipRect:裁剪区域
        */
        paintPy.onPaintBorder = function (view, paint, clipRect) {
            onPaintBorderDefault(view, paint, clipRect);
            if (view.viewType == "pdata") {
                paint.drawRect(view.borderColor, 1, 0, 0, 0, view.size.cx, view.size.cy);
            }
        };

        /*
        * 重置所有的大小
        */
        let resizeAll = function () {
            canvasPy.width = document.documentElement.clientWidth;
            canvasPy.height = document.documentElement.clientHeight;
            scaleCanvas(paintPy);
            updateViewDefault(paintPy.views);
            updatePyromoter(pyrometer);
            onPyrometerTime(pyrometer);
            invalidate(paintPy);
        };

        /*
        * 重置大小
        */
        window.onresize = function () {
            resizeAll();
        };

        /*
        * 旋转监听
        */
        window.onorientationchange = function () {
            resizeAll();

        };

        for (let i = 0; i < 100; i++) {
            let pData = new PyrometerData;
            pData.key = i;
            pData.text = i;
            pData.value = Math.random() * 1000 + 100;
            pData.open = Math.random() * 90 + 10;
            pData.close = Math.random() * 90 + 10;
            pData.size = new FCSize(0, 0);
            pData.location = new FCPoint(pyrometer.size.cx, pyrometer.size.cy);
            pData.backColor = null;
            pData.borderColor = "rgb(0,0,0)";
            addViewToParent(pData, pyrometer);
        }
        pyrometer.views.sort((m, n) => {
            if (m.value > n.value) {
                return -1;
            }
            else if (m.value < n.value) {
                return 1;
            }
            else return 0;
        });
        updateViewDefault(paintPy.views);
        updatePyromoter(pyrometer);
        onPyrometerTime(pyrometer);
        invalidateView(pyrometer);

    </script>
</body>
</html>
